{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit L35_modEvacuationAuto;

interface

uses Classes,
     modClasses,
     L05_modFlotteTracking,
     L10_modClassesAlerteAtt,
     L20_modClassesConstruction,
     L30_modClassesWithDB,

     modGalaxiePlanetes,
     modFlotteVaisseauxChoix,

     modUnitAndDefInfos,
     modGidToStr,
     
     modBaseType,
     modParsingClassIMenuLeft,
     modPlanete;





   
type


    TPlayerWithEvacuationAuto = class(TPlayerWithDB)
    private
        // la défense sera multipliée par ce nombre
        FRatioDefense    : double;

        // pareil pour la flotte à quai
        FRatioFlotteAQuai: double;

        

        //function xEvacuationSurChampDeRuine(Vaisseaux: TCollectionVaisseauSelInfos; BDD: TCollectionGalaxiePlanete): integer;


        // Evaluation de la flotte attaquante à partir de la chaine de caractère de la page aperçu
        // correspondant aux vaisseaux
        function EvaluationFlotteAttaquante(Chaine: string): integer;

        // Même chose mais pour un type de vaisseaux
        function EvaluationTokenFlotteAttaquante(Token: string): integer;


        
        
        // Cette procédure déclenche l'action d'évacuation
        // C'est à dire EVACUE la flotte
        // Il faut donc l'appeller au bon moment, c'est à dire peu de temps
        // avant l'impact
        //procedure DeclencheEvaForThisPlanete(p: TPlanetLocation);

        
        procedure DoDebugEva(const Msg: string);


        
    public
        //property EvacuationRatioOwnDefense    : double read FRatioDefense     write FRatioDefense;
        //property EvacuationRatioOwnFlotteAQuai: double read FRatioFlotteAQuai write FRatioFlotteAQuai;
        procedure UpdateInternalFromConf; override;



        // public pour permettre de tester manuellement cette fonction
        function EvacuationSurChampDeRuineOuInactif(p: TPlanetLocation; ClickSurRetourDans: int64): integer;


        procedure OnTimer; override;

        procedure ShowInternal; override;

        constructor Create;
    end;

implementation


uses modAlarmeAttaque,
     SysUtils,
     gnugettext,
     sFonctionsChaines,
     modFormulesDuJeu,

     modParsingClass,

     modLanguageParsing,
     Math,

     ESBDates;

procedure TPlayerWithEvacuationAuto.UpdateInternalFromConf;
begin
    FRatioFlotteAQuai    := Conf.EvacuationPourcentagePropreFlotte   / 100.0;
    FRatioDefense        := Conf.EvacuationPourcentablePropreDefense / 100.0;
end;

constructor TPlayerWithEvacuationAuto.Create;
begin

    inherited Create;

    
        // la défense sera multipliée par ce nombre
        FRatioDefense     := 0.7;

        // pareil pour la flotte à quai
        FRatioFlotteAQuai := 0.4;

end;



procedure TPlayerWithEvacuationAuto.OnTimer;
label lblSkipAlerteAtt, lDoEvaSwitch;
var i: integer;
    peAttack: PAlarmeAttack;
    xDiff: int64;

    x, y: double;
    aEval: double;
    iEval: integer;
begin
    inherited OnTimer;

    
    if IsLoggedAndCanDoSomething = false then begin
       if AlerteAttaqueGestion.IsAttacked then begin
          DoDebugEva(_('Attention: Autre opération en cours et attaque subie en cours'));
       end;
       exit;
    end;



{$IFNDEF NO_EVA}
    if AlerteAttaqueGestion.Count > 0 then begin

       for i := 0 to AlerteAttaqueGestion.Count - 1 do begin
           peAttack := AlerteAttaqueGestion.Items[i];

           if peAttack.FlotteExistePlus = false then begin
              // la flotte attaquante est encore présente

              if UnitsInfos = nil then begin
                 DoDebugEva(_('Echec: Informations des unités non définies'));


              end else if (iMustRelogin = false) and (peAttack.EvacuationAutomatique = aaeNonDefinit) then begin
                 // l'action à effectuer n'est pas encore définit

                 if (peAttack.ScoreFlotteAQuai < 0) or (peAttack.ScoreDefense < 0) then begin
                    // change de planète de manière sure
                    if ChangePlanete(peAttack.Arrivee, true) < 0 then begin
                       // echec de changement de planète...
                       DoDebugEva(_('Echec de changement de planète...'));
                       goto lblSkipAlerteAtt;
                    end;

                 end;

                 if peAttack.ScoreFlotteAQuai < 0 then begin
                    // on n'a pas encore calculé le score de la flotte à quai
                    DoDebugEva('Calcul du score de la flotte à quai en : ' + mbtPlanetLocationToStr(peAttack.Arrivee));

                    if ChangePlanete(peAttack.Arrivee) < 0 then begin
                       // echec de changement de planète...
                       DoDebugEva('Echec de changement de planète...');
                       goto lblSkipAlerteAtt;
                    end;

                    
                    if RetreiveFlotte1Page > 0 then begin
                       cFlotteVaisseaux.VaisseauxList.CalculStats(UnitsInfos);

                       peAttack.ScoreFlotteAQuai := cFlotteVaisseaux.VaisseauxList.ScoreFlotte;

                       DoDebugEva('Score Flotte à quai: ' + sfcFormatStrToMilliersP(peAttack.ScoreFlotteAQuai));


                    end else begin
                       DoDebugEva(_('Echec de calcul du score de la flotte à quai (echec de la page flotte1)'));
                    end;
                 end;

                 
                 if peAttack.ScoreDefense < 0  then begin
                    // on n'a pas encore calculé le score de la défense
                    DoDebugEva('Calcul du score de la défense en : ' + mbtPlanetLocationToStr(peAttack.Arrivee));

                    if ChangePlanete(peAttack.Arrivee) < 0 then begin
                       // echec de changement de planète...
                       DoDebugEva(_('Echec de changement de planète...'));
                       goto lblSkipAlerteAtt;
                    end;

                    if ProceedUpdateElement(mliDefense) > 0 then begin
                       peAttack.ScoreDefense := curPlanete.cElements.CalculScoreDefense(UnitsInfos);

                       DoDebugEva('Score défense: ' + sfcFormatStrToMilliersP(peAttack.ScoreDefense));


                    end else begin
                       DoDebugEva(_('Echec de calcul du score de la défense (echec de la page "defense") (définit à 0)'));
                       peAttack.ScoreDefense := 0;
                    end;

                 end;

                 if peAttack.ScoreFlotteAttaquante < 0 then begin
                    // on n'a pas encore calculé le score de la flotte attaquante
                    // OU
                    // le niveau d'espionnage ne permet pas d'en connaitre le type de vaisseau et ni le nombre

                    if peAttack.VaisseauxAttaquant = '' then begin
                       // pas d'information de flotte...
                       // le niv d'espionnage est trop faible


                    end else begin
                       peAttack.ScoreFlotteAttaquante := EvaluationFlotteAttaquante(peAttack.VaisseauxAttaquant);

                       if peAttack.ScoreFlotteAttaquante < 0 then begin
                          peAttack.VaisseauxAttaquant := '';
                          DoDebugEva(format(_('Score flotte attaquante: Indéterminable (ou erreur) (Vaisseaux: %s)'), [peAttack.VaisseauxAttaquant]));
                       end else begin
                          DoDebugEva('Score flotte attaquante: ' + sfcFormatStrToMilliersP(peAttack.ScoreFlotteAttaquante));
                       end;

                    end;

                 end;

              end; // FUnitsInfos = nil



lDoEvaSwitch:
              
              case peAttack.EvacuationAutomatique of
                  aaeNonDefinit: begin
                      // cherche à savoir si on doit l'évacuer (perte de combat)
                      // où si on peut la laisser à quai (on gagne alors la bataille)

                      // avant de déclencher une erreur, on vérifie que le robot n'a pas effectué
                      // d'erreur pour cause de relogin
                      if iMustRelogin then begin
                         // le robot doit se relogger
                         // on attend qu'il effectue son relogin
                         DoDebugEva('Le robot n''est plus loggé (MustRelogin), on déterminera l''ordre à effectuer plus tard');


                      end else begin

                         if (peAttack.VaisseauxAttaquant = '') or (UnitsInfos = nil) then begin
                            DoDebugEva('Score flotte attaquante indéterminable -> On évacuera la flotte');
                            peAttack.EvacuationAutomatique := aaeEvacuerEnAttente;

                         end else begin
                            if peAttack.ScoreFlotteAttaquante < 0 then begin
                               // bizarre, normalement dans ce cas là on devrait avoir peAttack.VaisseauxAttaquant = ''

                               if (peAttack.ScoreDefense < 0) or (peAttack.ScoreFlotteAQuai < 0) then begin
                                  // erreur critique...
                                  DoDebugEva(_('FATALE ERREUR'));
                               end;

                               DoDebugEva(_('Erreur d''enchainement de vérification -> On évacuera la flotte'));
                               peAttack.EvacuationAutomatique := aaeEvacuerEnAttente;

                            end else begin
                               // ok, on connait le score de la flotte attaquante
                               // et on connait obligatoirement le score de la flotte à quai
                               // et de la défense

                               if (peAttack.ScoreDefense < 0) or (peAttack.ScoreFlotteAQuai < 0) then begin
                                  // Erreur fatale
                                  DoDebugEva(_('FATALE ERREUR (2) -> On évacuera la flotte'));
                                  peAttack.EvacuationAutomatique := aaeEvacuerEnAttente;

                               end else begin
                                  // calcul qui va gagner la bataille

                                  DoDebugEva(format(_('Score flotte à quai: %d  (Ratio: %f)'), [peAttack.ScoreFlotteAQuai, FRatioFlotteAQuai]));
                                  DoDebugEva(format(_('Score défense: %d  (Ratio: %f)'), [peAttack.ScoreDefense, FRatioDefense]));
                                  DoDebugEva(format(_('Score flotte attaquante: %d'), [peAttack.ScoreFlotteAttaquante]));



                                  y := peAttack.ScoreFlotteAQuai;
                                  y := y * FRatioFlotteAQuai;
                                  DoDebugEva(format(_('Score flotte à quai après modification: %f'), [y]));


                                  x := peAttack.ScoreDefense;
                                  x := x * FRatioDefense;
                                  DoDebugEva(format(_('Score défense après modification: %f'), [x]));

                                  
                                  // evaluation totales des unités défensives
                                  aEval := x + y;
                                  iEval := trunc(aEval);

                                  DoDebugEva(format(_('Evaluation unités totales défensives: %f (%d)'), [aEval, iEval]));


                                  if iEval < peAttack.ScoreFlotteAttaquante then begin
                                     // La flotte attaquante va gagner
                                     DoDebugEva(_('La flotte attaquante va GAGNER -> On évacuera la flotte à quai'));

                                     peAttack.EvacuationAutomatique := aaeEvacuerEnAttente;

                                  end else begin
                                     if Conf.EvacuationSeulementSiOnPerdLaBataille then begin
                                        // on évacue seuelement si on perd, on évacue rien
                                        // MAIS, il se peut que se soit une attaque groupée...

                                        DoDebugEva(_('La flotte attaquante va PERDRE -> On n''évacuera PAS la flotte à quai'));
                                        peAttack.EvacuationAutomatique := aaeNeRienFaire;

                                     end else begin
                                        // on évacue dans tous les cas
                                        DoDebugEva(_('La flotte attaquante va PERDRE -> Mais les options indiquent que l''on doit quand même évacuer la flotte'));
                                        peAttack.EvacuationAutomatique := aaeEvacuerEnAttente;

                                     end;

                                  end;

                               end; // Score de défense, ou de flotte à quai < 0

                            end;  // Flotte attaquante score < 0

                         end; // Flotte attaquante inconnue

                      end; // iMustRelogin
                      
                  end; // cas aaeNonDefinit


                  aaeNeRienFaire: begin
                     // on ne fait rien
                     // CEPENDANT, il se peut que la planète se fasse MIPer entre temps
                     // avant l'impact, on vérifie si la défense est toujours opérationnelle

                     if peAttack.DateImpactLocal > LastCurrDate then begin
                        // l'impact n'a pas encore eut lieu
                        xDiff := peAttack.DateImpactLocal - LastCurrDate;

                        if xDiff < 150 then begin
                           // impact dans moins de 180 secondes
                           DoDebugEva('Moins de 150 secondes avant impact, on évalue à nouveau la défense pour savoir si elle n''est pas été détruite à coup de MIP');

                           if ChangePlanete(peAttack.Arrivee, true) < 0 then begin
                              // echec de changement de planète...
                              // "On fait comme si la défense existait toujours" ??
                              DoDebugEva('Echec de changement de planète...');

                              DoSleep(1500);

                              DoDebugEva('Réessaye...');
                              if ChangePlanete(peAttack.Arrivee, true) < 0 then begin
                                 DoDebugEva('Echec de changement de planète (seconde tentative) -> On fait comme si la défense existait toujours');
                                 DoDebugEva('Donc la flotte ne sera pas évacuée');
                                 peAttack.EvacuationAutomatique := aaeAEteEvacue;
                                 goto lblSkipAlerteAtt;
                              end;
                           end;


                           if ProceedUpdateElement(mliDefense) > 0 then begin
                              iEval := curPlanete.cElements.CalculScoreDefense(UnitsInfos);

                              if (peAttack.ScoreDefense > 0) and (iEval < peAttack.ScoreDefense) then begin
                                 // la défense à diminuer
                                 DoDebugEva('Score défense: ' + sfcFormatStrToMilliersP(iEval));
                                 DoDebugEva('ATTENTION: La défense a diminué... -> On évacue la flotte');
                                 peAttack.EvacuationAutomatique := aaeEvacuerEnAttente;
                                 goto lDoEvaSwitch;
                              end;

                           end else begin
                              DoDebugEva(_('Echec de calcul du score de la défense (echec de la page "defense")'));
                           end;

                           // on considère ici que la flotte est à l'abri
                           peAttack.EvacuationAutomatique := aaeAEteEvacue;
                        end;

                     end;

                  end;


                  aaeEvacuerEnAttente: begin

                       if peAttack.DateImpactLocal > LastCurrDate then begin
                          // l'impact n'a pas encore eut lieu
                          xDiff := peAttack.DateImpactLocal - LastCurrDate;

                          if peAttack.DelaiAvantImpactEva < 1 then begin
                             // attaque que l'on vient de détecter, on calcul la durée
                             // aléatoire pour l'évacuation avant impact
                             peAttack.DelaiAvantImpactEva := Conf.EvacuationDeFlotteDelaiAvantImpact;

                             Randomize;
                             peAttack.DelaiAvantImpactEva := peAttack.DelaiAvantImpactEva + Random(Conf.EvacuationDeFlotteDelaiAvantImpactRandom);

                             if Conf.EvacuationActive = false then begin
                                DoDebugEva(format(_('La flotte NE sera PAS évacuée %d secondes avant l''impact car l''option d''évacuation n''a pas été cochée'), [peAttack.DelaiAvantImpactEva]));
                             end else begin
                                DoDebugEva(format(_('La flotte sera évacuée %d secondes avant l''impact'), [peAttack.DelaiAvantImpactEva]));
                             end;

                          end;

                          
                          if xDiff < peAttack.DelaiAvantImpactEva then begin
                             // impact dans moins de 180 secondes

                             if Conf.EvacuationActive then begin
                                DoDebugEva(format(_('Moins de %d secondes avant impact, on évacue la flotte...'), [peAttack.DelaiAvantImpactEva]));


                                if (Conf.EvacuationDeFlotteRetourDelaiEnable) and (Conf.EvacuationDeFlotteRetourDelai > 0) then begin
                                   Randomize;
                                   EvacuationSurChampDeRuineOuInactif(peAttack.Arrivee, Conf.EvacuationDeFlotteRetourDelai + Random(Conf.EvacuationDeFlotteRetourDelaiRandom));

                                end else begin
                                   EvacuationSurChampDeRuineOuInactif(peAttack.Arrivee, 0);

                                end;

                             end else begin
                                DoDebugEva(format(_('Moins de %d secondes avant impact, la flotte devrait être évacuée mais l''option n''a pas été cochée...'), [peAttack.DelaiAvantImpactEva]));

                             end;

                             // on met à jour le flag
                             peAttack.EvacuationAutomatique := aaeAEteEvacue;
                          end;

                       end else begin
                          // l'impact a eut lieu
                          // on aurait du évacuer la flotte avant...
                          // l'impact ayant eut lieu, on devrait avoir:
                          // peAttack.FlotteExistePlus = true
                          // et on arrive alors jamais ici
                          DoDebugEva(_('L''impact a eut lieu sans que le déclencheur d''évacuation fut exécuté'));
                          peAttack.EvacuationAutomatique := aaeAEteEvacue;
                       end;


                  end;


                  aaeAEteEvacue: begin
                       // la flotte a déjà été évacuer
                       // le rappel de celle-ci est géré par le FlotteTracking


                  end;

              end; // case EvacuationAutomatique
              
           end; // peAttack.FlotteExistePlus = false

       end; // boucle pour chaque élément de l'alerte d'attaque

    end; // alerte d'attaque non vide

{$ENDIF}

lblSkipAlerteAtt:

end;

procedure TPlayerWithEvacuationAuto.ShowInternal;
begin
        inherited ShowInternal;

        DoDebug('@@@@@ Evacuation  @@@@@');

{$IFNDEF NO_EVA}
        // evacuation disponible
        DoDebugExtended('Info', 1);
{$ELSE}
        // pas disponible
        DoDebugExtended('Info', 0);
{$ENDIF}

        // la défense sera multiplié par ce nombre
        DoDebugExtended('RatioDefense', FRatioDefense);

        // pareil pour la flotte à quai
        DoDebugExtended('RatioFlotteAQuai', FRatioFlotteAQuai);


end;





// cette fonction prend un token en entrée
// c'est à dire: "Large Cargo 7" par exemple
function TPlayerWithEvacuationAuto.EvaluationTokenFlotteAttaquante(Token: string): integer;
var xPos: integer;
    VaisseauxStr, VaisseauxNb: string;
    iNb, vGID: integer;
    VaisseauxInfos: PUnitInfos;
begin

   Token := trim(Token);

   xPos := LastDelimiter(' :', Token);

   if xPos < 2 then begin
      Result := -1;
      exit;
   end;


   VaisseauxStr := trim(copy(Token, 1, xPos - 1));
   VaisseauxNb  := copy(Token, xPos + 1, maxint);

   VaisseauxNb := sfcRemplace(VaisseauxNb, '.', '');

   if sfcChaineContientQueDesChiffres(VaisseauxNb) = false then begin
      // echec d'identification du nombre de vaisseaux
      DoDebugEva('Echec d''identification du nombre de vaisseaux (Token:' + Token + ')');
      Result := -2;
      exit;
   end;

   try
      iNb := StrToIntDef(VaisseauxNb, -1);
   except
      iNb := -1;
   end;

   if iNb < 1 then begin
      // erreur
      DoDebugEva('Echec de conversion du nombre de vaisseaux (Token:' + Token + ')');
      Result := -3;
      exit;
   end;

   // obtient le gid pour ce type de vaisseaux
   vGID := GidToStr.GetGIDFromStr(VaisseauxStr);

   if vGID < 0 then begin
      // non trouvé...
      DoDebugEva('Echec de recherche de l''ID du vaisseaux (GID) (Token:' + Token + ')');
      Result := -4;
      exit;
   end;

   VaisseauxInfos := UnitsInfos.Get_Pointeur(vGID);

   if VaisseauxInfos = nil then begin
      // vaisseau non trouvé
      DoDebugEva('Echec de recherche des informations du vaisseaux (Units) (Token:' + Token + ')');
      Result := -5;
      exit;
   end;

   Result := VaisseauxInfos.ScoreDef * iNb;

end;


function TPlayerWithEvacuationAuto.EvaluationFlotteAttaquante(Chaine: string): integer;
var CurrTok: string;
    i, c: integer;
    tEval: integer;
begin
    if length(Chaine) < 3 then begin
       // chaine vide
       // tech espionnage trop faible certainement
       Result := -1;
       exit;
    end;

    // Nombre de vaisseaux: 2492 &lt;br&gt;Vaisseau de bataille 2147&lt;br&gt;Bombardier 345&lt;br&gt;
    // converti par la classe de parsing en:

    // Large Cargo 7; Cruiser 2
    Result := 0;


    // chaque type de vaisseaux est séparé par un ; par la classe de parsing
    // la classe de parsing prend aussi le soin d'enlever la chaine qui indique
    // le nombre de vaisseaux
    c := sfcTokenCount(Chaine, ';');

    for i := 1 to c do begin
       CurrTok := sfcTokenGet(Chaine, i, ';');

       tEval := EvaluationTokenFlotteAttaquante(CurrTok);

       if tEval >= 0 then begin
          // peut être égal à 0 si c'est des sondes par exemple
          // mais c'est déconseillé car il se peut que les sondes soient utilisées comme tampon
          Result := Result + tEval;

       end else begin
          // echec d'analyse...
          DoDebugEva('Echec d''analyse pour le token');
          Result := -5;
          break;
       end;

    end;

end;



procedure TPlayerWithEvacuationAuto.DoDebugEva(const Msg: string);
begin
{$IFDEF DEBUG}
   inherited DoDebug(_('Evacuation - ') + Msg);
{$ENDIF}
end;


function TPlayerWithEvacuationAuto.EvacuationSurChampDeRuineOuInactif(p: TPlanetLocation; ClickSurRetourDans: int64): integer;
var TempDB: TCollectionGalaxiePlanete;
    pInfos, cibleInfos: TPlaneteInfo;
    bNoRecycleur: boolean;
    Cible : TPlanetLocation;

    pVaisseauxList: TCollectionVaisseauSelInfos;

    trajetDistance, trajetDuree, iConsomation, x: integer;

    TotalRessource, r: integer;


    pInfosMission: TFlotteEnvoiData;
    pRessourceData: TOGRessourceAll;
begin

{$IFNDEF NO_EVA}
    if ClickSurRetourDans > 0 then begin
       DoDebugEva('Evacuation avec retour de la flotte dans: ' + IntToStr(ClickSurRetourDans) + ' secondes');

    end else begin
       DoDebugEva('Evacuation sans retour de la flotte');
    end;

    

    if ChangePlanete(p, true) < 0 then begin
       // echec de changement de planète
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Echec changement de planète');

       Result := -1;
       exit;
    end;


    pInfos := allPlanetes.GetPlanete(p);

    if pInfos = nil then begin
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Planète inconnue de l''empire...');
       //Result := -2;
       //exit;
    end;

    // essaye d'évacuer la flotte dans le champ de ruine de la planète
    // il devrait normalement exister puisqu'on essaye de recycler la flotte courante
    // MAIS il se peut qu'il n'y ai pas de recycleur

    

    // on télécharge la page de flotte pour connaitre la flotte à quai
    // ET les ressources (surtout le deutérium)
    // ET SURTOUT pour connaitre les flottes existantes pour pouvoir identifier
    // la flotte que l'on va envoyer

    
    if RetreiveFlotte1Page < 1 then begin
       // erreur de téléchargement de la page de flotte
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Echec telechargement page flotte');
       Result := -3;
       exit;
    end;

    // Le deutérium actuel se situe ici:
    DoDebugEva('EvacuationSurChampDeRuineOuInactif - Deutérium disponible: ' + sfcFormatStrToMilliersP(curPlanete.FLastRessources.Deuterium));


    if cFlotteVaisseaux.URLToPost = '' then begin
       // flotte max atteint...
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Flotte maximal atteint, impossible d''évacuer la flotte');
       Result := -7;
       exit;
    end;


    TotalRessource := curPlanete.FLastRessources.Metal + curPlanete.FLastRessources.Cristal + curPlanete.FLastRessources.Deuterium;


    pVaisseauxList := cFlotteVaisseaux.VaisseauxList;

    if pVaisseauxList.GetNbVaisseauxDispo(CNT_GID_VAISSEAUX_RECYCLEUR) <= 0 then begin
       // pas de recycleur
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Pas de recycleur à quai, l''action exploiter ne sera pas essayée');
       bNoRecycleur := true;

    end else begin
       bNoRecycleur := false;
    end;

    // sélectionne TOUTE la flotte
    pVaisseauxList.SelectionneTousLesVaisseaux;

    x := pVaisseauxList.GetCapacitePourVaisseauxSel;
    DoDebugEva('EvacuationSurChampDeRuineOuInactif - Capacité de transport: ' + sfcFormatStrToMilliersP(x));
    DoDebugEva('EvacuationSurChampDeRuineOuInactif - Ressources totales: ' + sfcFormatStrToMilliersP(TotalRessource));

    // Vérifie si la capacité de fret peut couvrir toutes les ressources
    if x < TotalRessource then begin
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Capacité de transport trop petite pour évacuer toutes les ressources');

       // on ne peut pas tout évacuer, il va falloir faire un choix
       // on peux aussi d'abord construire quelques choses (ou de la def) puis évacuer
       // ce que l'on peut
       pRessourceData.Metal      := trunc(curPlanete.FLastRessources.Metal * 0.8);
       pRessourceData.Cristal    := trunc(curPlanete.FLastRessources.Cristal * 0.9);
       pRessourceData.Deuterium  := curPlanete.FLastRessources.Deuterium;


    end else begin
       // on peut tout évacuer
       pRessourceData.Metal      := curPlanete.FLastRessources.Metal;
       pRessourceData.Cristal    := curPlanete.FLastRessources.Cristal;
       pRessourceData.Deuterium  := curPlanete.FLastRessources.Deuterium;
    end;





    // la vitesse reste à 10%
    pInfosMission.Vitesse   := 1;

    // et les ressources sont les même:
    pInfosMission.Ressources := pRessourceData;




       // commence à faire une estimation de la quantité de deutérium pour le voyage de TOUTE la flotte
       trajetDistance := mfdgGetDistance(p, p);
       trajetDuree    := mfdgGetDurationTrajet100p(p, p, pVaisseauxList.GetSpeedUsed, 10, Conf.UniversSpeedFactorFlotte);
       iConsomation   := pVaisseauxList.GetConsomationDeut(trajetDistance, trajetDuree);

       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Stats pour cible locale:');
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Distance: ' + sfcFormatStrToMilliersP(trajetDistance));
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Duree: ' + sfcFormatStrToMilliersP(trajetDuree));
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Consomation: ' + sfcFormatStrToMilliersP(iConsomation));

       if iConsomation > curPlanete.FLastRessources.Deuterium then begin
          // trop peu de deutérium à quai pour évacuer la flotte vers le champ de ruine ou la lune de la planète
          // de la planète actuelle
          // par conséquent, il y a aussi TROP PEU de deutérium pour évacuer la flotte vers un autre endroit
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Cible locale -> Pas assez de deutérium');
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Impossible d''évacuer la flotte');
          Result := -7;
          exit;
       end;



    // ATTENTION:
    // la planète peut correspondre à une lune
    // bien que l'on a fait attention dans le cas particulier où il existait une lune
    // il faut également faire attention lorsque l'attaque est sur une lune
    


    if NoT(bNoRecycleur) then begin
       // on essaye d'envoyer la flotte sur le champ de ruine de la planète
       // fait une tentative d'envoi sur le champ de ruine local
       pInfosMission.Cible     := p;
       pInfosMission.CibleType := ctRuines;
       pInfosMission.Ordre     := ooExploiter;

       r := ProceedEnvoiDeFlotteAndRetour(@pInfosMission, ClickSurRetourDans);
       if r > 0 then begin
          // réussi
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Champ de ruine de la planète locale ok');
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Flotte évacuée');
          Result := 1;
          exit;
       end else begin
          if r = CNT_ERREUR_ENVOI_DE_FLOTTE then begin
             // erreur d'envoi de la flotte
             DoDebugEva('EvacuationSurChampDeRuineOuInactif - Champ de ruine de la planète locale échec');

             // essaye un autre champ de ruine ??
             // mais il faut repasser par la page1 avant...
             // cependant on va perdre les vaisseaux sélectionner
             // donc on triche un peu et on ne télécharge que la page sans
             // refaire le parsing
             r := RetreiveFlotte1Page(true);

             if (r < 1) then begin
                DoDebugEva('EvacuationSurChampDeRuineOuInactif - Erreur flotte 1 (skip)');
                r := RetreiveFlotte1Page(true);

             end;

          end else begin
             // erreur de programmation du retour de flotte
             DoDebugEva('EvacuationSurChampDeRuineOuInactif - Champ de ruine de la planète locale -> Erreur de programmation du retour de flotte');
             Result := 1;
             exit;
          end;

       end;

    end;


    // si on arrive ici, c'est que l'on ne peut pas envoyer la flotte sur le champ de ruine local
    // on vérifie si il y a une lune
    if mbtIsLune(p) then begin
       // l'attaque se déroule sur une lune, il suffit d'envoyer la flotte sur la planète
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - L''attaque est sur une lune, on envoit la flotte sur la planète');


       // Obtient les coordonnées de la planète
       Cible := p;
       Cible.Position := mbtGetRealPosition(p.Position);


       // On évacue sur la planète
       pInfosMission.Cible     := Cible;
       pInfosMission.CibleType := ctPlanete;
       pInfosMission.Ordre     := ooBaser; // ooTransport; // en mode transport, quand on fait retour on peut se faire phalanger


       if ProceedEnvoiDeFlotteAndRetour(@pInfosMission, ClickSurRetourDans, true) > 0 then begin
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Flotte évacuée sur la planète');
          Result := 1;
          exit;
       end;

    end else begin
       // essaye de savoir si la planète possède une lune
       Cible := p;
       Cible.Position := p.Position + CNT_POSITION_LUNE;

       cibleInfos := allPlanetes.GetPlanete(Cible);

       if cibleInfos <> nil then begin
          // ok, une lune existe, on envoi la flotte vers la lune
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - L''attaque est sur une planète qui possède une lune -> on envoit la flotte sur la lune');


          // la cible doit correspondre à celle d'une planète (le type est spécifié en dessous)
          pInfosMission.Cible     := p;
          pInfosMission.CibleType := ctLune;
          pInfosMission.Ordre     :=  ooTransport; // on peut laisser transport car on part de la 'planète'

          if ProceedEnvoiDeFlotteAndRetour(@pInfosMission, ClickSurRetourDans, true) > 0 then begin
             DoDebugEva('EvacuationSurChampDeRuineOuInactif - Flotte évacuée sur la lune');
             Result := 1;
             exit;
          end;

       end else begin
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Pas de lune trouvée sur la planète en cours');
       end;

    end;


    // pour l'instant, on ne scanne par les systèmes solaires alentour
    // on envoi la flotte sur une de nos planètes les plus proches (si il y en a dans la galaxie)


    cibleInfos := allPlanetes.GetPlaneteLaPlusProchePourEvacuation(p);

    if cibleInfos = nil then begin
       // pas de cible trouvée...
       DoDebugEva('EvacuationSurChampDeRuineOuInactif - Pas de cible trouvée -> Pas d''évacuation...');
       Result := -8;
       exit;
    end;

    // une planète a été trouvé

    pInfosMission.Cible     := cibleInfos.FLocation;
    if mbtIsLune(cibleInfos.FLocation) then begin
       pInfosMission.CibleType := ctLune;
    end else begin
       pInfosMission.CibleType := ctPlanete;
    end;
    pInfosMission.Ordre     := ooTransport;

       if ProceedEnvoiDeFlotteAndRetour(@pInfosMission, ClickSurRetourDans) > 0 then begin
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Flotte évacuée sur une de nos planètes');
          Result := 1;
          exit;
       end else begin
          DoDebugEva('EvacuationSurChampDeRuineOuInactif - Echec d''évacuation');
          Result := -99;
       end;


(*
    TempDB := TCollectionGalaxiePlanete.Create;

    ProceedGalaxieScan(TempDB, p.Galaxie, p.SystemSolaire - 1, p.SystemSolaire + 1, 0);

    TempDB.Free;
*)


{$ELSE}
      DoDebugEva('#################################');
      DoDebugEva('Version sans évacuation');
      DoDebugEva('Flotte non évacuée');
      DoDebugEva('#################################');
{$ENDIF}

end;


end.
